CrackMe2 by FiNS // HTB Team tutorial by ToMKoL [c4U]

Nudzilo mi sie ostatnio i tak przypadkiem wpadlo mi w rece cm2 FiNS'a. Nikt nie pokusil sie
o napisanie tutoriala, wiec zaczynamy. Najpierw opdalamy crackme i nic. Nie chodzi, moze
to wina odpalonego SI. Popatrzmy wiec czy cm jest spakowane. Nie jest, wiec dobra nasza.
Patrzymy na stringi i tabele importow. Widzimy createfilea i string lotr.jrrt, sprobujmy?
W SI zakladamy pulapke na createfile i lecimy:

sub_40102D	proc
	push    0
	push    20h
	push    3
	push    0
	push    0
	push    80000000h
	push    offset aLotr_jrrt	;lotr.jrrt
	call    CreateFileA
	inc     eax
	jz      short loc_401027	;exitprocess
	dec     eax
	push    0
	push    offset NumberOfBytesRead
	push    0B0h
	push    offset Buffer
	push    eax
	call    ReadFile
	mov     eax, NumberOfBytesRead
	xor     eax, 77h
	xor     eax, 0D9h
	jnz     short loc_401027	;exitprocess
	mov     eax, offset Buffer
loc_401075:
	xor     dword ptr [eax], 656C6C6Fh
	sub     dword ptr [eax], 21212121h
	add     eax, 4
	cmp     byte ptr [eax], 0
	jnz     short loc_401075
	mov     esi, offset unk_403192
	mov     edi, offset Buffer
	mov     ecx, 0B0h
	repe cmpsb
	jnz     short loc_401027	;exitprocess
	retn
sub_40102D      endp

ta procka jest wywolywana zaraz po getmodulehandle. Jesli ktorys jump skoczy to wylecimy
z crackme. Tak wiec najpierw cm sprawdza dlugosc pliku:

x^77h^D9h=0 a wiec zeby poznac poprawna w SI piszemy ? d9^77 i mamy x=AEh (174d)

tworzymy plik lotr.jrrt i wypelniamy go dowolnymi 174 znakami. Potem tylko procka,
ktora sprawdza poprawnosc pliku:

	mov     eax, offset Buffer
loc_401075:
	xor     dword ptr [eax], 656C6C6Fh
	sub     dword ptr [eax], 21212121h
	add     eax, 4
	cmp     byte ptr [eax], 0
	jnz     short loc_401075
	mov     esi, offset unk_403192
	mov     edi, offset Buffer
	mov     ecx, 0B0h
	repe cmpsb
	jnz     short loc_401027	;exitprocess
	retn

Jesli przejdzie to pokaze sie nam dialog. Dobra teraz pora obrocic procke i otrzymac
poprawny plik. Napiszemy maly generatorek (zrodla zalaczone). Mamy plik wiec lecimy dalej.
Teraz po uruchomieniu crackme pokazuje ladny dialog. Mozemy sobie poklikac. My wpisujemy
cos w edit'a, zakladamy pulapke w SI na getdlgitemtexta. Mamy jakies obliczenia, ale od
razu powiem, ze jest to procka fake. W jakims res-edit (ja lubie exescope) zobaczmy id
przyciksu OK jest 65h (101d). W ida od razu widac, ze po kliknieciu przycisku wykonywany
jest najpierw jakis kod, a dopiero potem pobierany jest serial przez getdlgitemtexta.
Zobaczmy co FiNS liczy i dlaczego liczy na buforze gdzie pobierany jest serial. Po kodzie
radze sie poruszac przy pomocy F8, jest pelno fake call'i, po ktorych mozemy wyleciec z
kodu. Tak wiec zakladamy pulapke na getdlgitemtexta, jak sie zlapie czyscimy ja i zakladamy
pulapke na adres 401189 czyli bpx cs:401189. Tu zaczyna sie kod wykonywany przed pobraniem
tekstu przez getdlgitemtexta. Najpierw jednak musimy wstawic kilka nop'ow w kod. FiNS uzyl
metody na wylaczenie ekranu pod SI, ktora dziala chyba tylko na systemach 9x. Tak wiec jak
tylko zobaczymy in xx,xx lub out xx,xx to stajac na tej linijce dajemy a eip i piszemy nop,
enter i po sprawie. Teraz czas na procke sprawdzajaca poprwnosc seriala (wyrzucone smieci):

	push     00403304
	push     20
	push     0D
	push     [00403344]
	push     004011CD
	jmp      [USER32!SendMessageA]
	pop      eax	;w eax adres naszego seriala
	push     eax

w ten sposob FiNS pobiera hasleko zaraz po nacisnieciu OK. Czyli pobieranie przez getdlg...
to lipa. Zobaczmy jak sprawdzane jest haslo:

	mov     eax, [eax]
	xor     ebx, ebx
	xor     ecx, ecx
	xor     edx, edx
	inc     edx
	sahf
	cmovp   ebx, edx
	cmovnz  ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	sahf
	cmovb   ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	sahf
	cmovns  ecx, edx
	add     ebx, ecx
	ror     eax, 1
	xor     ecx, ecx
	sahf
	cmovnb  ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	sahf
	cmovnp  ecx, edx
	add     ebx, ecx
	rol     eax, 3
	add     esp, 4
	xor     ecx, ecx
	sahf
	cmovz   ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	sahf
	cmovs   ecx, edx
	add     ebx, ecx
	rol     eax, 6
	xor     ecx, ecx
	sahf
	pushfw
	cmovns  ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	popfw
	pushfw
	cmovb   ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	popfw
	pushfw
	cmovz   ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	popfw
	cmovp   ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	ror     eax, 1
	sahf
	cmovnp  ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	sahf
	cmovb   ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	rol     eax, 3
	sahf
	cmovz   ecx, edx
	add     ebx, ecx
	xor     ecx, ecx
	sahf
	cmovns  ecx, edx
	add     ebx, ecx
	ror     eax, 2
	stc
	sbb     ebx, 0Fh
	jnz     loc_4014D1
	bswap   eax
	rol     al, 2
	xor     al, 1Fh
	mov     ecx, 8
loc_4012B6:
	bt      eax, 0
	jnb     loc_4014D1
	ror     al, 1
	loop    loc_4012B6
	xor     ecx, 4
	bswap   eax
	xor     al, 1
loc_4012CB:
	test    al, 1
	jz      loc_4014D1
	test    al, 2
	jnz     loc_4014D1
	ror     al, 2
	loop    loc_4012CB
	pop     eax

ta procka sprawdza poprawnosc pierwszego dword'a. Nic tylko puscic szybkiego bruta (src
dolaczone). I juz mamy pierwszy poprawny dword, ktory wyglada tak - W58T. A wiec zmieniamy
serial na W58Txxxxxx i lecimy dalej. Dalej mamy sprawdzanie 2 dword'a za pomoca 1 i 4, ale
to narazie pominiemy. Zajmiemy sie policzeniem 3 i 4 dword'a:

 loc_401340:
	add     eax, 8
	mov     ebx, [eax]
	add     eax, 4
	mov     eax, [eax]
	bswap   eax
	bswap   ebx
	mov     ecx, 18273645h
	add     ecx, ebx
	sub     ecx, 3783D21Dh
	add     ecx, 2487AAB1h
	imul    ecx, 2
	inc     ecx
	push    eax
	imul    eax, 2
	sub     ecx, eax
	pop     eax
	add     ecx, 48AC2D51h
	mov     edi, 2461B328h
	add     edi, eax
	add     edi, 153F6BDCh
	xchg    eax, edi
	xor     edx, edx
	idiv    dword_40327A ;2
	xchg    eax, edi
	add     edi, ebx
	sub     edi, 1669089Ah
	cmp     ecx, edi
	jnz     loc_4014D1

ta procka sprawdza poprawnosc 3 i 4 dword'a. Jesli ecx i edi rowne to 3 i 4 dword poprawne.

oznaczenia - x to ebx gdzie jest 3 dword a y to eax gdzie jest 4 dword seriala

(18273645h+x-3783D21Dh+2487AAB1h)*2+1-(y*2)+48AC2D51h=(2461B328h+y+153F6BDCh)/2+x-1669089Ah

(x+052B0ED9)*2+1-(2y)+48AC2D51h=(39A11F04h+y)/2+x-1669089Ah

2x+0A561DB3h-2y+48AC2D51h=1CD08F82h+y/2+x-1669089Ah

2x-2y+53024B04h=y/2+x+066786E8h

x-3/2y+4C9AC41Ch=0

x=5/2y-4C9AC41Ch

Ponizej jest druga, ktora realizuje to samo tylko w inny sposob:

loc_40327E:
	mov     ecx, 742CD105h
	sub     ecx, 42825C0Ah
	add     ecx, ebx
	sub     ecx, 2D47B0C1h
	imul    ecx, 2
	sub     ecx, eax
	add     ecx, 2E370D23h
	mov     edi, eax
	add     edi, 7A2103B0h
	xchg    eax, edi
	idiv    dword_40327A
	xchg    eax, edi
	add     edi, 185AAB49h
	sub     edi, 36B82A4Ch
	add     edi, ebx
	retn

ta procka sobie gnije w sekcji data, po powrocie ecx jest porownywany z edi. Jesli rowne
to 3 i 4 dword seriala sa poprawne, sprobujmy je policzyc:

oznaczenia - x to ebx gdzie jest 3 dword a y to eax gdzie jest 4 dword seriala

(742CD105h-42825C0Ah+x-2D47B0C1h)*2-y+2E370D23h=(y+7A2103B0h)/2+185AAB49h-36B82A4Ch+x

(0462C43Ah+x)*2-y+2E370D23h=y/2+3D1081D8h+185AAB49h-36B82A4Ch+x

08C58874h+2x-y+2E370D23h=y/2+1EB302D5h+x

36FC9597h+2x-y-y/2-1EB302D5h-x=0

184992C2h+x-3/2y=0

x=3/2y-184992C2h

i teraz mamy dwa rownania z ktorych policzymy 3 i 4 dword poprawnego seriala:

x=5/2y-4C9AC41Ch i x=3/2y-184992C2h

5/2y-4C9AC41Ch=3/2y-184992C2h

5/2y-3/2y=4C9AC41Ch-184992C2h

y=3451315Ah

tak wiec mamy 4 dword - 4Q1Z, liczymy 3 z dowolnego rownania

x=5/2*3451315Ah-4C9AC41Ch

x=36303745h

i mamy 3 dword - 607E, pozostalo tylko obliczyc 2 dword ze wzoru:

	mov     ebx, [eax+4] ;2 dword
	mov     ecx, [eax+0Ch] ;4 dword
	mov     eax, [eax] ;1 dword
	xor     eax, ebx
	xor     eax, ecx
	rol     eax, 5
	add     eax, 0DEAD00h
	xor     eax, 5636EE58h
	inc     eax
	ja      loc_4014D1

0-1=FFFFFFFFh^5636EE58h=A9C911A7h-0DEAD00h=A8EA64A7h ror 5=3D475325h^5A315134h=
67760211h^54383557h=334E3746h

i mamy drugi dword, teraz wystarczy go obrocic i wychodzi nam - F7N3. A cale haslo
wygalda tak - W58TF7N3607E4Q1Z. Po wpiasniu dostaje info z gratulacjami za zlamanie cm.

To by bylo na tyle. Crackme dosc fajnie napisane, zaszyfrowane fragmenty kodu, procki fake,
troche fake call'i, wylaczenie ekranu pod SI. Jako bonus powiem, ze fake pass wygalada tak
xxxxxxxx7250zzzz - za x dowolna wartosc bo nie jest sprawdzane a dla z nie ma rozwiazania.
Dolaczylem zrodla brutali i generatorka pliku klucza.

tom_c4u@o2.pl - piszcie, najwyzej nie odpisze
www.crackmes.prv.pl - chyba nie musze pisac